package com.zmzncs.lmtc.common.websocket;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@ServerEndpoint(value = "/webSocket/{customerId}")
@Component
@Slf4j
public class WebsocketServer {

    public static Map<String, List<WebsocketServer>> webSocketSet = new ConcurrentHashMap<>();
    public Session session;
    public String customerId;    //  客户id
    public final static String separator = "@";   //  客户id与随机数分隔符

    //  消息
    public static Map<String, Object> messageMap = new HashMap<>();

    @OnOpen
    public void onOpen(@PathParam("customerId") String customerId, Session session, EndpointConfig config) {
        this.session = session;
        this.customerId = customerId;

        log.info("客户【{}】加入连接", customerId + separator + session.getId());

        List<WebsocketServer> sessionServerList = webSocketSet.get(customerId);
        if(sessionServerList != null && sessionServerList.size() > 0){
            sessionServerList.add(this);
        } else {
            webSocketSet.put(customerId,  new ArrayList<>(Collections.singletonList(this)));
        }

        //  计算在线设备数
        getOnLineNum();

        try {
            //  连接成功回复
            session.getBasicRemote().sendText("onOpenSuccess");
        } catch (Exception e) {
            log.error("连接成功后回复消息失败【{}】", e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 关闭连接
     */
    @OnClose
    public void onClose() {
        log.info("客户【{}】关闭连接", customerId);

        try {
            List<WebsocketServer> websocketServerList = webSocketSet.get(customerId);
            //  使用迭代器的删除方法删除
            if(websocketServerList != null && websocketServerList.size() > 0){
                log.info("在list中删除客户【{}】", customerId);
                websocketServerList.removeIf(websocketServer -> websocketServer == this);
                if(websocketServerList.size() == 0) {
                    log.info("在map中删除客户【{}】", customerId);
                    webSocketSet.remove(customerId);
                }
            }
        } catch (Exception e) {
            log.error("客户【{}】关闭消息异常【】", customerId, e);
            e.printStackTrace();
        }

        //  计算在线设备数
        getOnLineNum();
    }

    /**
     * 收到消息
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        try {
            //  控制台不打印心跳消息
            if(!message.equals("ping")){
                log.info("收到客户【{}】的回复消息：【{}】", customerId + separator + session.getId(), message);

                //  如果消息不为ping，清除消息
                messageMap.remove(message);
                //  清除其他失效消息
                for(Map.Entry<String, Object> entry: messageMap.entrySet()) {
                    if(new Date().getTime() > ((Date) entry.getValue()).getTime()){
                        log.info("清除过期消息：【{}】", entry.getKey());
                        messageMap.remove(entry.getKey());
                    }
                }
            }

            //  响应心跳
            session.getBasicRemote().sendText("pong");
        } catch (Exception e) {
            log.error("响应消息-客户【{}】发送消息异常，异常信息【{}】", customerId + separator + session.getId(), e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     *  连接异常
     */
    @OnError
    public void onError(Session session, Throwable error) {
        try {
            log.error("客户【{}】连接错误，消息【{}】", customerId + separator + session.getId(), error.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    void getOnLineNum() {
        //  计算在线设备数
        long onLineNum = 0;  //  计算在线设备数
        for (Map.Entry<String, List<WebsocketServer>> entry : webSocketSet.entrySet()) {
            List<WebsocketServer> list = entry.getValue();
            onLineNum += list.size();
        }
        log.info("在线设备数量：【{}】", onLineNum);
    }


}